package com.sun.apilimitrate.service;

import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class RedissonRateLimitService {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 尝试获取令牌，如果获取不到则进行防抖处理
     * @param key 限流的唯一标识，例如接口路径+用户ID
     * @param permits 每次请求需要的令牌数量
     * @param rate 令牌产生速率
     * @param rateInterval 令牌产生的时间间隔
     * @param unit 时间单位
     * @return true表示获取到令牌，可以继续处理请求；false表示被限流，需要进行防抖处理
     */
    public boolean tryAcquire(String key, long permits, long rate, long rateInterval, RateIntervalUnit unit) {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
        // 设置限流器的速率，这是一个幂等操作，只需设置一次
        rateLimiter.trySetRate(RateType.OVERALL, rate, rateInterval, unit);
        return rateLimiter.tryAcquire(permits);
    }

    /**
     * 针对特定接口设置防抖策略
     * 例如：限制某个用户对某个接口每秒最多请求2次
     */
    public boolean debounceForApi(String userId, String apiPath) {
        String key = "rate_limit:" + apiPath + ":" + userId;
        // 每秒产生2个令牌，每个请求消耗1个令牌
        return tryAcquire(key, 1, 2, 1, RateIntervalUnit.SECONDS);
    }

    /**
     * 针对特定接口设置防抖策略（带超时时间）
     * 如果获取不到令牌，会等待指定时间看是否有令牌可用
     */
    public boolean debounceForApiWithTimeout(String userId, String apiPath, long timeout, TimeUnit unit) {
        String key = "rate_limit:" + apiPath + ":" + userId;
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
        rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);
        return rateLimiter.tryAcquire(1, timeout, unit);
    }
}